"""Other methods need to wait for login, but may be called concurrently

All the paraphernalia in Service class is to make Login() lock other
methods, but allow other methods to be called concurrently

"""


import threading
import sys
import time
import random
import datetime

class Service(object):
    def __init__(self, *args, **kwargs):
        self.Ev_login = threading.Event() # This Event is managed by Login()
        # Events are initially set so that wait() calls don't block (initially)
        self.Ev_login.set() 
        # This Event is managed by _IncCounter()() and _DecCounter()
        self.Ev_counter = threading.Event() 
        self.Ev_counter.set()
        # This lock is used to make incrementing and decrementing the counter
        # thread-safe
        self.L_counter = threading.Lock()
        # Counts how many "other" methods are currently entered
        self._counter = 0
    
    def _IncCounter(self):
        with self.L_counter:
            self._counter += 1
            # This will keep Login() from entering
            self.Ev_counter.clear()
        
    def _DecCounter(self):
        with self.L_counter:
            self._counter -= 1
            if self._counter <= 0:
                # This will allow Login() from entering again
                self.Ev_counter.set()
    
    def Login(self):
        self.Ev_counter.wait() # Waits until al other methods have exited
        self.Ev_login.clear() # Blocks all other methods from entering again
        # Increases this counter even here because
        # I don't want Login() to be entered twice
        self._IncCounter()
        try:
            print "\n>>> Login..."
            time.sleep(4)
            print "\nLogin END"
        finally:
            self.Ev_login.set()
            self._DecCounter()
    
    def Plant(self):
        self.Ev_login.wait()
        self._IncCounter()
        try:
            print "\n>>> Plant..."
            time.sleep(4)
            print "\nPlant END"
        finally:
            self._DecCounter()
            
    def Harvest(self):
        self.Ev_login.wait()
        self._IncCounter()
        try:
            print "\n>>> Harvest..."
            time.sleep(4)                        
            print "\nHarvest END"
        finally:
            self._DecCounter()

    def Sleep(self):
        self.Ev_login.wait()
        self._IncCounter()
        try:
            print "\n>>> Sleep..."
            time.sleep(4)
            print "\nSleep END"
        finally:
            self._DecCounter()
            

class Caller(threading.Thread):
    methodName = None

    def run(self):
        id = random.randint(0, 99999)
        print "\n", self.__class__.__name__, " wants to call the ", self.methodName, " method (%d)" % id
        eval("self.service.%s()" % self.methodName)
        print "\n", self.__class__.__name__, " CALLED the ", self.methodName, " method (%s)" % datetime.datetime.today()
        
class Caller1(Caller):
    methodName = "Login"

class Caller2(Caller):
    methodName = "Harvest"

class Caller3(Caller):
    methodName = "Sleep"

class Caller4(Caller):
    methodName = "Plant"

service = Service()
aa = [Caller1, Caller2, Caller3, Caller4]
for a in aa:
    obj = a()
    obj.service = service
    obj.start()
print "----Aparasse----"
